/*
 *	armboot - startup code for arm920t cpu-core
 *	copyright  (c)  2009 yongwei.tang  <daxia.tang@gmail.com
 *
 *    本程序是arm920t核cpu的初始化程序，负责完成第一阶段的引导工作
 *    ，并将提供第二阶段引导程序的入口。
 *
 */

 # include	<start.h>

 /*
  *    程序开始
  */

.global	_start
_start:
	b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq

_undefined_instruction:	.word undefined_instruction
_software_interrupt:	.word software_interrupt
_prefetch_abort:	.word prefetch_abort
_data_abort:		.word data_abort
_not_used:		.word not_used
_irq:			.word _irq
_fiq:			.word _fiq

/*
 *
 * Startup Code (reset vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 */
 _TEXT_BASE:
 	.word	TEXT_BASE

.global	_armboot_start
_armboot_start:
	.word	_start
.global	_bss_start
_bss_start:
	.word	_bss_start
.global _bss_end
_bss_end:
	.word	_end

/*
 * reset code
 */

reset:
	/*
	 * set the cpu to SVC32 mode
	 * 设置cpu模式为svc
	 */
	mrs	r0,cpsr
	bic	r0,r0,#0x1f
	orr	r0,r0,#0xd3		/* I=1,F=1,T=0,[0:4]=10111 */	
	msr	cpsr,r0

# define pWTCON		0x53000000
# define INTMSK		0x4A000008	/* Interupt-Controller base addresses */
# define INTSUBMSK	0x4A00001C
# define UPLLCON	0x4c000004
# define MPLLCON	0x4c000008
# define CLKDIVN	0x4C000014	/* clock divisor register */
# define CAMDIVN	0x4C000018

/*
 * 设置PLL必须先设置UPLL，再等约七个机器周期
 * UPLL= [(MDIV+8)*Fin]/[(PDIV+2)*2^SDIV]
 * MPLL= [2*(MDIV+8)*12]/[(PDIV+2)*2^SDIV]
 */ 
# define U_MDIV		127<<12
# define U_PDIV		2<<4
# define U_SDIV		1
# define M_MDIV		56<<12
# define M_PDIV		2<<4
# define M_SDIV		2

	/*
	 * turn off the watchdog
	 */

	ldr     r0, =pWTCON
	mov     r1, #0x0
	str     r1, [r0]

	/*
	 * mask all IRQs by setting all bits in the INTMR 
	 * 屏蔽所有的中断
	 */
	mov	r1, #0xffffffff
	ldr	r0, =INTMSK
	str	r1, [r0]
	ldr	r1, =0x3ff
	ldr	r0, =INTSUBMSK
	str	r1, [r0]

	/* FCLK:HCLK:PCLK = 1:4:8 */
	/* default FCLK is 400 MHz ! */
	ldr	r0, =CLKDIVN
	mov	r1, #5			/* [2:1]=2,[0]=1 */
	str	r1, [r0]
	ldr	r0, =CAMDIVN
	mov	r1, #0			/* [9]=0,[8]=0 */
	str	r1,[r0]

	mrc	p15,0,r0,c1,c0,0	/*
	orr	r0,r0,#0xc0000000	 * 设置总线模式，asynchronous bus mode
	mcr 	p15 0,r0,c1,c0,0	 */


	ldr	r0,=UPLLCON		 /* 设定UPLL */
	ldr	r1,=U_MDIV|U_PDIV|U_SDIV /* 0x7f021 */
	str	r1,[r0]
	nop				 /*
	nop				  * UPLL设定后，最少经过7个时钟才稳定
	nop				  */
	nop
	nop
	nop
	nop
	ldr	r0,=MPLLCON		 /* 设置MPLL */
	ldr	r1,=M_MDIV|M_PDIV|M_SDIV /* 0x38022 */
	str	r1,[r0]

cpu_init_crit:
	/*
	 * flush v4 I/D caches
	 * 使无效整个I/D cache
	 * 使无效整个TLB
	 */
	mov	r0, #0
	mcr	p15, 0, r0, c7, c7, 0	/* flush v4 cache */
	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */

	/*
	 * disable MMU stuff and caches
	 * 禁用整个MMU和cache
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #0x00002300	/* [13]=0, [9:8]=0 */
	bic	r0, r0, #0x00000087	/* [7]=0,[2:0]=0 */
	orr	r0, r0, #0x00000002	/* [2]=1 */
	orr	r0, r0, #0x00001000	/* [12]=1 */
	mcr	p15, 0, r0, c1, c0, 0

	/*
	 * Go setup Memory and board specific bits prior to relocation.
	 */
	mov	ip, lr          /* perserve link reg across call */
	bl	lowlevel_init   /* go setup pll,mux,memory */
	mov	lr, ip          /* restore link */
	mov	pc, lr          /* back to my caller */
